package org.hilo.boot.core.shiro;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

/**
 * 自定义FormAuthenticationFilter，支持验证SessionId
 * 
 * 基于 user agent：几乎不会变，但是很可能重复，且容易猜测和伪造
 * ，能拿到sessionId自然也能拿到user agent。 
 * 因此，user agent可以用于验证身份，验证失败，证明修改了user-agent，
 * 但是验证成功并不能说明是正常请求。
 * 
 * 另外，即使加上user-agent验证，也无法避免XSS和中间人攻击 ，建议使用HTTPS并防范XSS。
 * 
 * 参考资料： 
 * <p>https://en.wikipedia.org/wiki/Session_fixation </p>
 * <p>https://blog.csdn.net/h_mxc/article/details/50542038 </p>
 * <p>https://www.cnblogs.com/tomcuper/p/7802560.html </p>
 * 
 * @see SecuritySessionIdGenerator
 * 
 * @author zollty
 * @since 2018年4月3日
 */
@Deprecated
public class SessionVerifyAjaxAccessControlFilter extends AjaxAccessControlFilter {
    
    /**
     * 防Session攻击：根据User-Agent，验证使用的SessionID是否和生成它时处于同一个浏览器下
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        Subject subject = SecurityUtils.getSubject();
        boolean ret = subject.isAuthenticated();
        if (!ret) { // 未登录，直接返回
            return false;
        }
        // 增加 User-Agent 检查
        if (subject.getSession() != null && subject.getSession().getId() != null) {
            if (request instanceof HttpServletRequest) {
                HttpServletRequest wrequest = (HttpServletRequest) request;
                String userAgent = wrequest.getHeader("User-Agent");
                if (userAgent != null) {
                    ret = SessionEncoder.matches(userAgent, subject.getSession().getId().toString());
                } else {
                    return false;
                }
            }
        }
        return ret;
    }

}
